package com.xframe.xdal.core.model.sqlbuilder.proc;

import com.xframe.xdal.core.constant.DalConstants;
import com.xframe.xdal.core.model.mapping.IColumnMapping;
import com.xframe.xdal.core.model.sqlbuilder.BaseSqlBuilder;
import com.xframe.xdal.core.model.sqlbuilder.BuilderContext;
import com.xframe.xdal.core.model.sqlbuilder.DbExpression;
import com.xframe.xdal.core.model.sqlbuilder.SqlExpression;
import com.xframe.xdal.core.util.XReflect;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 功能描述: manyinsert
 *
 * @version 1.0
 * @author：xufeng
 * @date: 2022/10/9 17:45
 **/
@Slf4j
public class DefManyInsertBuilder extends BaseSqlBuilder {

    /**
     * manyinsert sql语句模板
     * @return
     */
    public String getSQL() {
        return "INSERT INTO %s(%s) VALUES %s";
    }

    @Override
    public SqlExpression build(BuilderContext context) {
        //参数集合
        List<Object> paramList = new ArrayList<>();
        Map<String, String> map = createStr(context, paramList);
        String colStr = map.get("colStr");
        String valueStr = map.get("valueStr");
        String sql = String.format(getSQL(), context.getNameConvert().toName(context.getTableInfo().getName()), colStr, valueStr);
        return new SqlExpression(sql, paramList,context.getDataSourceTypeEnums());
    }


    /**
     * 获取col values string col:id,label,code  values: (?,?,?),(?,?,?)
     *
     * @param context   上下文
     * @param paramList 参数list
     * @return map  colStr: id,label,code  valueStr:(?,?,?),(?,?,?)
     */
    public Map<String, String> createStr(BuilderContext context, List<Object> paramList) {
        List<IColumnMapping> columnMapingList = context.getTableInfo().getColumnMappingList();
        StringBuilder colstrBuilder = new StringBuilder();
        StringBuilder valstrBuilder = new StringBuilder();
//        Integer dataSize = context.getDataSize();
//        if (dataSize <= 0) {
//            dataSize = 1;
//        }
        valstrBuilder.append(DalConstants.SQL_LEFT_PARENTHESIS);
        columnMapingList.forEach(item -> createStrBuilder(item, colstrBuilder, valstrBuilder, context));

        String valStr = valstrBuilder.toString();
        // 获取构造过的valuesStrBuilder
        Collection datas = context.getData().getCollection();
        StringBuilder valuesStrBuilder = createValueStringBuilder(datas.size(), valStr);

        //获取参数list
        createValParamList(paramList, datas.size(), columnMapingList, context);
        String colStr = colstrBuilder.toString();
        String valueStr = valuesStrBuilder.toString();
        if (colStr.endsWith(DalConstants.SQL_SEPARATION)) {
            colStr = colStr.substring(0, colStr.length() - 1);
        }
        if (valueStr.endsWith(DalConstants.SQL_SEPARATION)) {
            valueStr = valueStr.substring(0, valueStr.length() - 1);
        }
        Map<String, String> map = new HashMap<>();
        map.put("colStr", colStr);
        map.put("valueStr", valueStr);
        return map;
    }



    /**
     * 生成col val 的拼接字符串 以“,”分割，末尾也有“,” builder
     * colstrBuilder格式:  id,label,code,  valstrBuilder格式: (?,?,?,
     *
     * @param columnMaping  字段
     * @param colstrBuilder 列构造器
     * @param valstrBuilder 值构造器
     * @param context       上下文
     */
    public void createStrBuilder(IColumnMapping columnMaping,
                                 StringBuilder colstrBuilder, StringBuilder valstrBuilder,
                                 BuilderContext context) {
        colstrBuilder.append(context.getNameConvert().toName(columnMaping.getName()));

        if(BuilderContext.useDbObjectFlag) {
            if (columnMaping.getUseDbObjectFlag()) {
                String dbExp = DbExpression.getDbExpression().getExpression(columnMaping.getDbExpression(), context.getDataSourceTypeEnums());
                valstrBuilder.append(dbExp);
            } else {
                valstrBuilder.append(DalConstants.SQL_PLACE_HOlDER);
            }
        }else {
            valstrBuilder.append(DalConstants.SQL_PLACE_HOlDER);
        }

        colstrBuilder.append(DalConstants.SQL_SEPARATION);
        valstrBuilder.append(DalConstants.SQL_SEPARATION);
    }


    /**
     * 获取valuesStrBuilder (?,?,?),(?,?,?),(?,?,?),
     *
     * @param dataSize 获取数量
     * @param valStr   单个valStr (?,?,?,
     */
    public StringBuilder createValueStringBuilder(Integer dataSize, String valStr) {
        Integer copyDataSize = dataSize;
        StringBuilder valueStrBuilder = new StringBuilder();

        // 循环拼接values
        while (copyDataSize > 0) {
            valueStrBuilder.append(valStr.substring(0, valStr.length() - 1)).append(DalConstants.SQL_RIGHT_PARENTHESIS).append(DalConstants.SQL_SEPARATION);
            copyDataSize--;
        }
        return valueStrBuilder;
    }


    /**
     * 获取参数list
     *
     * @param paramList        参数list 对象
     * @param dataSize         数据集合长度
     * @param columnMapingList 字段映射list
     * @param context          上下文
     */
    public void createValParamList(List<Object> paramList, Integer dataSize,
                                   List<IColumnMapping> columnMapingList, BuilderContext context) {
        // 单行参数
        List<Object> rowParamList = new ArrayList<>();

        // 获取参数信息
        Collection collection = context.getData().getCollection();
        for(Object item:collection){
            columnMapingList.forEach(columnMapping -> createValRowList(columnMapping,item, context, rowParamList));
            paramList.addAll(rowParamList);
            rowParamList.clear();
        }

    }


    /**
     * 获取参数列表
     *
     * @param columnMaping 字段
     * @param context      上下文
     * @param paramList    参数list
     */
    public void createValRowList(IColumnMapping columnMaping, Object item,BuilderContext context,
                                 List<Object> paramList) {
        if(BuilderContext.useDbObjectFlag) {
            if (!columnMaping.getUseDbObjectFlag()) {
                paramList.add(XReflect.getFieldValue(item, columnMaping.getFieldName()));
            }
        }else {
            paramList.add(XReflect.getFieldValue(item, columnMaping.getFieldName()));
        }
    }
}
